<template>
    <div class="tags-container">
        <!-- <el-tag effect="plain">首页</el-tag> -->
        <!-- 通过遍历的方式实现多个tag -->
        <el-tag @contextmenu.native.prevent="rightClick(index, $event)" @close="tagClose(index, item.path)"
            @click="$router.push(item.path)" v-for="item, index in pathes"
            :effect="$route.path === item.path ? 'dark' : 'plain'" :closable="item.path !== '/'">{{ item.meta.title
            }}</el-tag>
        <!-- 这一份是一开始传递x和y的方式控制位置的 -->
        <!-- <TagContextMenu :show="showMenu" :x="menuX" :y="menuY" /> -->
        <!-- 这是第一次做关闭当前进行子传父的写法 -->
        <!-- <TagContextMenu :show="showMenu" ref="menu" @hide="showMenu = false" @close-current="closCurrent" /> -->
        <!-- 每次点击 菜单，如果都要做一次子传父，太麻烦了，所以一性全都传回来 -->
        <TagContextMenu :show="showMenu" ref="menu" @hide="showMenu = false" @item-click="itemClickHandle" />
    </div>
</template>

<script>
import { onMounted } from 'vue'
import TagContextMenu from './TagContextMenu.vue'
export default {
    components: { TagContextMenu },
    data() {
        return {
            // 1. 准备好一个数组
            pathes: [{
                path: '/',
                meta: {
                    title: '首页'
                }
            }],
            showMenu: false,
            menuX: 0,
            menuY: 0
        }
    },
    // 作用： 当一个数据变化，影响别的数据
    watch: {
        '$route.path': {
            handler() {
                // 去重 ， 如果当前路由已经在 数组里面了，就不再添加
                // 判断对象是否包含不能使用includes ， 使用 值来比较
                if (!this.pathes.find(item => item.path === this.$route.path)) {
                    this.pathes.push(this.$route)
                }
            }
        },
        // 数据，数据要求是响应式的 , 要求是一开始就存在的
        // 用法： 简写
        // pathes(newVal,oldVal){
        //     // 处理逻辑
        // },
        // 用法2：对象
        // pathes: {
        //     handler(){},
        //     // 立即监听 - 在监听数据初始化的时候也执行
        //     immediate:true,
        //     // 深度监听  - 如果监听的是对象，同时监听其属性
        //     deep: true
        // }
        // 用法3： 如果只想监听对象的某个属性来提高效率
        // "对象.属性"(){}
        // "$route.path"() {
        //     this.pathes.push(this.$route)
        // }
    },
    methods: {
        tagClose(index, path) {
            // 如果删除的刚好是 当前的路由 ，需要跳转到一个别的页面
            if (path === this.$route.path) {
                // 跳转到上一个页面
                this.$router.push(this.pathes[index - 1].path)
            }
            // 把被点击的 tag 移除 ， 事实上是移除 数组里面的 $route 对象
            // console.log(index);
            this.pathes.splice(index, 1)
        },
        rightClick(index, ev) {
            // console.log(event) // 这个写法是 window.event, 不推荐使用 ，这是一种远古的写法，是ie8及以下获取事件对象的方式
            // 事件修饰符
            // .prevent - 阻止默认行为
            // .stop - 阻止冒泡
            // .key  - 键盘事件对应的 按键码
            // .self - 仅仅自己生效，后代冒泡上来的不生效
            // .native  - 在组件上 给，组件的根标签 穿透事件
            this.showMenu = true;
            // 修改位置
            // this.menuX = ev.clientX;
            // this.menuY = ev.clientY;
            // console.log(this.menuX, this.menuY)

            // 控制右键菜单位置的方式2： ref
            // console.log(this.$refs.menu);
            // 方式2 可以直接操作 真实dom $el
            // this.$refs.menu.$el.style.top = ev.clientY + 10 + 'px'
            // this.$refs.menu.$el.style.left = ev.clientX + 10 + 'px'
            // 方式3： 让 组件 提供一个方法 ， 然后把 x,y 传入，在组件内部自己处理逻辑
            // this.$refs.menu.fnnnnnnn();
            // 我们调用，修改位置的方法
            this.$refs.menu.setPosition(ev.clientX, ev.clientY)
            // 调用一个传递index进入子组件的方法
            this.$refs.menu.giveIndex(index, this.pathes.length);
        },
        // closCurrent(index) {
        //     let path = this.pathes[index].path
        //     this.tagClose(index, path)
        //     this.showMenu = false;
        // } 
        itemClickHandle(index, cmd) {
            let path = ''
            // console.log(index, cmd);
            switch (cmd) {
                case 'refresh':
                    break;
                case 'close-current':
                    path = this.pathes[index].path
                    this.tagClose(index, path)
                    break;
                case 'close-other':
                    // 这样不行
                    // for (let i = 1; i < this.pathes.length; i++) {
                    //     if (i === index) {
                    //         continue;
                    //     } else {
                    //         this.pathes.splice(i, 1)
                    //         i--;
                    //     }
                    // }
                    path = this.pathes[index].path;
                    // 只留下对应的两个就行
                    this.pathes = this.pathes.filter((item, i) => i == 0 || i == index)
                    this.$router.push(path)
                    break;
                case 'close-left':
                    path = this.pathes[index].path
                    // 直接从1开始，删除 index -1 个就行
                    let temp = this.pathes.splice(1, index - 1);
                    // 如果被删除的tag里面有被激活的 ， 跳转到当前这个tag对应的path
                    let isCurrentPath = temp.find(item => item.path === this.$route.path)
                    if (isCurrentPath) {
                        this.$router.push(path)
                    }
                    break;
                case 'close-right':
                    break;
                case 'all':
                    break;
            }

            this.showMenu = false;
        },
        hideMenu() {
            this.showMenu = false;
        }
    },
    // 我们希望点击页面的任何位置，都能把 右键菜单隐藏
    // 于是我们给 document 注册点击事件
    mounted() {
        document.addEventListener('click', this.hideMenu)
    },
    // 如果我们有手动对dom进行 事件 之类的操作，一定要记得清理垃圾
    beforeDestroy() {
        document.removeEventListener('click', this.hideMenu)
    }
}
</script>
 
<style lang = "less" scoped>
.tags-container {
    padding: 10px;

    /deep/.el-tag {
        margin-right: 10px;
        position: relative;
        z-index: 1;
    }
}
</style>